/**
 * @license
 * Copyright 2021 Du Tian Wei
 * SPDX-License-Identifier: Apache-2.0
 */

OpenBlock.BlocklyParser.BlockToAST = (function () {
    function getFieldText(field) {
        if (typeof (field) == 'string') {
            return field;
        } else {
            return field?.text || "";
        }
    }
    function blockIntputs(block) {
        return block.values || block.inputs || {};
    }
    function blockStatements(block) {
        return block.statements || block.inputs || {};
    }
    function getBlockAST(b) {
        if (!b) {
            this._stack.markError(block, '缺少块');
            return;
        }
        let ASTFunc;
        let block;
        try {
            if (b.AST) {
                block = b;
                ASTFunc = b.AST;
                return b.AST(b);
            } else if (b.block) {
                block = b.block;
                ASTFunc = b.block.AST;
                return b.block.AST(b.block);
            } else if (b.shadow) {
                block = b.shadow;
                ASTFunc = b.shadow.AST;
                return b.shadow.AST(b.shadow);
            }
        } catch (e) {
            console.log("getBlockAST error", e, block, ASTFunc);
            return;
        }
        {
            debugger
            this._stack.markError(block, '没有AST');
            return;
        }
    }
    function BlocktoStatementDef(block) {
        let def = new StatementDef();
        if (block) {
            for (let cur = block; cur; cur = (cur.block ? cur.block.next : cur.next)) {
                let ast = getBlockAST(cur);
                if (ast instanceof Dummy) {
                    continue;
                } else if (ast instanceof VariableDeclaration) {
                    def.addVarDecl(ast);
                    let setAST = ast.makeSetLocalVariableValue();
                    def.addInstruction(setAST); // 声明包含初始化指令
                } else if ((ast instanceof Instruction)) {
                    def.addInstruction(ast);
                } else if (ast instanceof ErrorAST) {
                    console.warn(ast);
                } else {
                    // skip
                }
            }
        }
        return def;
    }

    function BlocktoStatementDefSafe(statements, name) {
        if (!(statements && statements[name])) {
            return new StatementDef();
        } else {
            return BlocktoStatementDef(statements[name]);
        }
    }

    function BlocktoExpr(_stack, currentBlock, block, errMsg) {
        if (!block) {
            _stack.markError(currentBlock, errMsg || '需要条件');
            return;
        }
        let ast = getBlockAST(block);
        if (!(ast instanceof Expr)) {
            _stack.markError(block, 'not expr');
        }
        return ast;
    }
    function BlocktoExpr2(_stack, curblock, blockValues, key, errMsg) {
        if (!blockValues) {
            _stack.markError(curblock, errMsg || '需要条件');
        }
        let block = blockValues[key];
        if (!block) {
            _stack.markError(curblock, errMsg || '需要条件');
            return;
        }
        let ast = getBlockAST(block);
        if (!(ast instanceof Expr)) {
            _stack.markError(block, 'not expr', ast);
        }
        return ast;
    }

    function toTextExpr(_stack, curblock, block) {
        let expr = BlocktoExpr(_stack, curblock, block);
        if (expr instanceof TextExpr) {
            return expr;
        } else {
            return new ToString(expr);
        }
    }
    return {
        dummy(block) {
            return new Dummy();
        },
        text_join(block) {
            if (!blockIntputs(block)) {
                return new TextConstExpr("");
            }
            let items = parseInt(
                block.extraState ?
                    block.extraState.itemCount :
                    block.mutation.items);
            let stack;
            for (let i = 0; i < items; i++) {
                let key = "ADD" + i;
                let value = blockIntputs(block)[key];
                if (value) {
                    if (!stack) {
                        stack = toTextExpr(this._stack, block, value);
                    } else {
                        stack = new TextJoin(stack, toTextExpr(this._stack, block, value));
                    }
                }
            }
            stack.setBlockId(block.id);
            return stack;
        },
        math_round(block) {
            let op = getFieldText(block.fields.OP);
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).NUM);
            let ast = new MathSingle();
            ast.setBlockId(block.id);
            ast.setOP(op);
            ast.setValue(value);
            let f2i = new F2I(ast);
            f2i.setBlockId(block.id);
            return f2i;
        },
        math_modulo(block) {
            let DIVIDEND = BlocktoExpr(this._stack, block, blockIntputs(block).DIVIDEND);
            let DIVISOR = BlocktoExpr(this._stack, block, blockIntputs(block).DIVISOR);
            let m = new Modulo();
            m.dividend = DIVIDEND;
            m.divisor = DIVISOR;
            m.setBlockId(block.id);
            return m;
        },
        math_number_property(block) {
            let prop = getFieldText(block.fields.PROPERTY);
            if (prop === 'PRIME') {
                this._stack.markError(block, "功能未实现");
            }
            let value1 = BlocktoExpr(this._stack, block, blockIntputs(block).NUMBER_TO_CHECK);
            switch (prop) {
                case 'EVEN':
                    // code = number_to_check + ' % 2 == 0';
                    {
                        let m = new Modulo(value1, new IntegerConstExpr(2));
                        let c = new Compare();
                        c.setOP("EQ");
                        c.setLeft(m);
                        c.setRight(new IntegerConstExpr(0));
                        c.setBlockId(block.id);
                        return c;
                    }
                    break;
                case 'ODD':
                    // code = number_to_check + ' % 2 == 1';
                    {
                        let m = new Modulo(value1, new IntegerConstExpr(2));
                        let c = new Compare();
                        c.setOP("EQ");
                        c.setLeft(m);
                        c.setRight(new IntegerConstExpr(1));
                        c.setBlockId(block.id);
                        return c;
                    }
                    break;
                case 'WHOLE':
                    // code = number_to_check + ' % 1 == 0';
                    {
                        let C1 = new FixRegister(value1);
                        let f2i = new F2I(C1);
                        f2i.setBlockId(block.id);
                        let c = new Compare();
                        c.setOP("EQ");
                        c.setLeft(f2i);
                        c.setRight(C1);
                        c.setBlockId(block.id);
                        C1.unfix();
                        return c;
                    }
                    break;
                case 'POSITIVE':
                    // code = number_to_check + ' > 0';
                    {
                        let c = new Compare();
                        c.setOP("GT");
                        c.setLeft(value1);
                        c.setRight(new FloatConstExpr(0));
                        c.setBlockId(block.id);
                        return c;
                    }
                    break;
                case 'NEGATIVE':
                    // code = number_to_check + ' < 0';
                    {
                        let c = new Compare();
                        c.setOP("LT");
                        c.setLeft(value1);
                        c.setRight(new FloatConstExpr(0));
                        c.setBlockId(block.id);
                        return c;
                    }
                    break;
                case 'DIVISIBLE_BY':
                    // var divisor = Blockly.JavaScript.valueToCode(block, 'DIVISOR',
                    //     Blockly.JavaScript.ORDER_MODULUS) || '0';
                    // code = number_to_check + ' % ' + divisor + ' == 0';
                    {
                        let d = BlocktoExpr(this._stack, block, blockIntputs(block).DIVISOR);
                        let m = new Modulo(value1, d);
                        let c = new Compare();
                        c.setOP("EQ");
                        c.setLeft(m);
                        c.setRight(new FloatConstExpr(0));
                        c.setBlockId(block.id);
                        return c;
                    }
                    break;
            }
        },
        math_random_int(block) {
            let r = new RandomInt();
            r.From = (BlocktoExpr(this._stack, block, blockIntputs(block).FROM));
            r.To = (BlocktoExpr(this._stack, block, blockIntputs(block).TO));
            r.setBlockId(block.id);
            return r;
        },
        math_random_float(block) {
            let r = new Random();
            r.setBlockId(block.id);
            return r;
        },
        math_constant(block) {
            let ast = new FloatConstExpr();
            let txt = getFieldText(block.fields.CONSTANT);
            switch (txt) {
                case "PI":
                    ast.number = Math.PI;
                    break;
                case "e":
                    ast.number = Math.E;
                    break;
                case "GOLDEN_RATIO":
                    ast.number = 1.6180339887498948482;
                    break;
                case "SQRT2":
                    ast.number = Math.SQRT2;
                    break;
                case "SQRT1_2":
                    ast.number = Math.SQRT1_2;
                    break;
                case "INFINITY":
                    ast.number = Number.POSITIVE_INFINITY;
                    ast.special = "POSITIVE_INFINITY";
                    break;
            }
            ast.setBlockId(block.id);
            return ast;
        },
        math_trig(block) {
            let op = getFieldText(block.fields.OP);
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).NUM);
            let ast = new MathSingle();
            ast.setOP(op);
            ast.setValue(value);
            ast.setBlockId(block.id);
            return ast;
        },
        math_trig_atan2(block) {
            let op = 'ATAN2';
            let ast = new ARITH();
            ast.setOP(op);
            ast.setLeft(BlocktoExpr(this._stack, block, blockIntputs(block).Y, "必须提供值"));
            ast.setRight(BlocktoExpr(this._stack, block, blockIntputs(block).X, "必须提供值"));
            ast.setBlockId(block.id);
            return ast;
        },
        math_single(block) {
            let op = getFieldText(block.fields.OP);
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).NUM);
            let ast = new MathSingle();
            ast.setOP(op);
            ast.setValue(value);
            ast.setBlockId(block.id);
            return ast;
        },
        native_call(block) {
            let mutationData;
            if (block.mutation) {
                mutationData = JSON.parse(decodeURI(block.mutation.text), Deserializer);
            } else {
                this._stack.markError(block, '没有函数信息');
            }
            // {
            //     "func": {
            //         "args": [],
            //         "returnType": {
            //             "name": "test.MainClass",
            //             "$__type": "StructFieldTypeStruct"
            //         },
            //         "name": "test.MainClass.ctor",
            //         "signature": "test.MainClass.ctor()Stest.MainClass;",
            //         "fullname": "test.MainClass.ctor",
            //         "scope": "global",
            //         "libHash": "qeIBnqtCRvMiD40tEynZSA==",
            //         "libIndex": 5,
            //         "libName": "Test",
            //         "$__type": "FunctionDef"
            //     },
            //     "skip": false
            // }
            // let func = OpenBlock.nativefunctions.check(mutationData.func, true);

            let ast;
            if ((!mutationData.ignoreReturnValue) && mutationData.func.returnType) {
                ast = new ValueNativeCall();
            } else {
                ast = new VoidNativeCall();
            }
            let func = OpenBlock.Env.matchNativeFunction(this._stack ? this._stack.info.src[0].env : block.fsm.src.env, mutationData.func);
            if (!func) {
                if (this._stack) {
                    this._stack.markError(block, (OpenBlock.i("找不到函数库") + ' ' + OpenBlock.i(mutationData.func.fullname)));
                }
                return ast;
            }
            ast.setFunc(func);
            let fields = block.fields || {};
            let values = blockIntputs(block) || {};
            if (values || fields) {
                func.args.forEach(arg => {
                    let value = values[arg.name];
                    if (value) {
                        let expr = BlocktoExpr(this._stack, block, value);
                        ast.setArg(arg.name, expr);
                    } else {
                        value = fields[arg.name];
                        if (value !== undefined) {
                            let v;
                            switch (arg.type.name) {
                                case 'String':
                                    v = new TextConstExpr(getFieldText(value));
                                    break;
                                case 'Number':
                                    v = new FloatConstExpr(parseFloat(value));
                                    break;
                                case 'Integer':
                                    v = new IntegerConstExpr(parseInt(value));
                                    break;
                                case 'Boolean':
                                    v = new IntegerConstExpr(!!value);
                                    break;
                                default:
                                    v = new RefExpr(value);
                                    break;
                            }
                            ast.setArg(arg.name, v);
                        } else if (this._stack) {
                            this._stack.markError(block, "请设置参数 " + OpenBlock.i(arg.name));
                        }
                    }
                });
            } else if (func.args.length > 0) {
                this._stack.markError(block, "请设置参数");
            }
            ast.setBlockId(block.id);
            return ast;
        },
        variables_self(block) {
            let ast = new Self();
            ast.setBlockId(block.id);
            return ast;
        },
        method_return(block) {
            let expr = null;
            if (blockIntputs(block) && blockIntputs(block).VALUE) {
                expr = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE, "必须提供值");
            }
            if (this._stack) {
                let functionInfo = this._stack.last([
                    'function',
                    'typed_procedures', 'on_event',
                    'on_message', 'on_message_struct', 'on_message_primary', 'on_message_with_arg']);
                if (functionInfo.ast.returnType) {
                    if (!expr) {
                        this._stack.markError(block, '必须提供返回值');
                    } else if (expr.astType && functionInfo.ast.returnType.name != expr.astType) {
                        this._stack.markError(block, '返回值类型不匹配');
                    }
                }
            }
            let ast = new Return();
            ast.setValue(expr);
            ast.setBlockId(block.id);
            return ast;
        },
        local_variable_get(block) {
            let ast = new GetLocalVariableValue();
            ast.setName(getFieldText(block.fields.VAR));
            ast.setBlockId(block.id);
            return ast;
        },
        local_variable_set(block) {
            let ast = new SetLocalVariableValue();
            ast.setName(getFieldText(block.fields.VAR));
            let value = BlocktoExpr(this._stack, block, blockIntputs(block) && blockIntputs(block).VALUE, "必须提供值");
            ast.setValue(value);
            ast.setBlockId(block.id);
            return ast;
        },
        local_variable_create(block) {
            if (!getFieldText(block.fields.NAME)) {
                this._stack.markError(block, '未指定名称');
            }
            if (!blockIntputs(block)) {
                this._stack.markError(block, '未指定值');
            }
            if (!blockIntputs(block).VALUE) {
                this._stack.markError(block, '未指定初始值');
            }
            let ast = new VariableDeclaration();
            let varInfo = JSON.parse(decodeURI(block.mutation.text), Deserializer);
            if (!varInfo) {
                this._stack.markError(block, '未获得变量信息');
            }
            varInfo = varInfo[0];
            if (!varInfo) {
                this._stack.markError(block, '未获得变量信息');
            } else {
                ast.type = varInfo.type;
            }
            ast.name = getFieldText(block.fields.NAME);
            ast.value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            ast.setBlockId(block.id);
            return ast;
        },
        typed_procedure_call(block) {
            let mutationData;
            if (block.mutation) {
                mutationData = JSON.parse(decodeURI(block.mutation.text), Deserializer);
            } else {
                mutationData = {
                    returnType: null,
                    args: []
                }
            }
            let methodName = getFieldText(block.fields.METHOD);
            if (methodName == null || methodName.length == 0) {
                this._stack.markError(block, OpenBlock.i('请选择要调用的函数'));
            }
            let moduleName = getFieldText(block.fields.MODULE);
            let fullName = moduleName ? methodName : '.' + methodName;
            let ast;
            if (mutationData.returnType && !mutationData.ignoreReturnValue) {
                ast = new ValueMethodCall();
                ast.setReturnType(mutationData.returnType.toCodeText());
            } else {
                ast = new VoidMethodCall();
            }
            ast.MethodName = fullName;
            if (blockIntputs(block)) {
                for (let i = 0; i < mutationData.args.length; i++) {
                    let arg = blockIntputs(block)['ARG' + i];
                    if (!arg) {
                        this._stack.markError(block, '没有设置第' + (i + 1) + "个参数");
                    }
                    let expr = BlocktoExpr(this._stack, block, arg);
                    ast.addArg(expr);
                }
            } else if (mutationData.args.length > 0) {
                this._stack.markError(block, OpenBlock.i("没有设置参数"));
            }
            ast.setBlockId(block.id);
            return ast;
        },
        typed_procedures(block) {
            let ast = new FunctionDef();
            let name = getFieldText(block.fields.NAME);
            ast.setName(name);
            if (this._stack) {
                this._stack.push(block);
                this._stack.setCurrentAST(ast);
                if (!name) {
                    this._stack.markError(block, OpenBlock.i("没有设定函数名称"));
                }
            } else if (!name) {
                throw new Error("没有设定函数名称");
            }
            if (blockStatements(block) && blockStatements(block).ARGS) {
                for (let field = blockStatements(block).ARGS; field; field = field.next) {
                    ast.addArg(getBlockAST(field));
                    if (field.block && !field.next) {
                        field = field.block;
                    }
                }
            }
            if (blockIntputs(block) && blockIntputs(block).RETURN) {
                ast.setReturnType(BlocktoExpr(this._stack, block, blockIntputs(block).RETURN));
            }
            try {
                ast.setBody(BlocktoStatementDef(block.next));
            } catch (e) {
                e.func = name;
            } finally {
                if (this._stack) {
                    this._stack.pop();
                }
            }
            ast.setBlockId(block.id);
            return ast;
        },
        logic_boolean(block) {
            let ast = new BooleanConstExpr();
            if (getFieldText(block.fields.BOOL) === 'TRUE') {
                ast.number = 1;
            } else {
                ast.number = 0;
            }
            ast.astType = 'Boolean';
            ast.setBlockId(block.id);
            return ast;
        },
        controls_if(block) {
            let ast = new IfControl();
            if (!blockIntputs(block)) {
                return ast;
            }
            // let ifthen = 1;
            // if (block.mutation) {
            //     if (block.mutation.elseif) {
            //         ifthen += parseInt(block.mutation.elseif);
            //     }
            // }
            let inputs = blockIntputs(block);
            let inputNames = Object.keys(inputs);
            inputNames.sort();
            inputNames.forEach((inputName) => {
                if (inputName.startsWith('IF')) {
                    let _if = BlocktoExpr(this._stack, block, inputs[inputName]);
                    let _then = BlocktoStatementDefSafe(blockStatements(block), 'DO' + inputName.substring(2));
                    ast.addPair(_if, _then);
                }
            })
            if (blockStatements(block).ELSE) {
                let _if = new IntegerConstExpr();
                _if.number = 1;
                let _then = BlocktoStatementDef(blockStatements(block).ELSE);
                ast.addPair(_if, _then);
            }
            ast.setBlockId(block.id);
            return ast;
        },
        controls_flow_statements(block) {
            let type = getFieldText(block.fields.FLOW);
            let ast;
            switch (type) {
                case "BREAK":
                    ast = new Break();
                    ast.setBlockId(block.id);
                    return ast;
                case "CONTINUE":
                    ast = new Continue();
                    ast.setBlockId(block.id);
                    return ast;
                default:
                    this._stack.markError(block, type);
            }
        },
        controls_whileUntil(block) {
            let mode = getFieldText(block.fields.MODE) === 'WHILE';
            if (!(blockIntputs(block) && blockIntputs(block).BOOL)) {
                this._stack.markError(block, '必须指定条件');
            }
            let bool = BlocktoExpr(this._stack, block, blockIntputs(block).BOOL);
            let statment = BlocktoStatementDefSafe(blockStatements(block), 'DO');
            let ast = new WhileUntil(mode, bool, statment);
            ast.setBlockId(block.id);
            return ast;
        },
        controls_repeat_ext(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TIMES)) {
                this._stack.markError(block, '必须指定次数');
            }
            let timesExpr = BlocktoExpr(this._stack, block, blockIntputs(block).TIMES);
            let statement = BlocktoStatementDefSafe(blockStatements(block), 'DO');
            let ast = new RepeatTimes(timesExpr, statement);
            ast.setBlockId(block.id);
            return ast;
        },
        controls_for(block) {
            let varName = getFieldText(block.fields.VAR);
            let stmt = BlocktoStatementDefSafe(blockStatements(block), 'DO');
            let fromExpr;
            let toExpr;
            let byExpr;
            if (blockIntputs(block)) {
                if (blockIntputs(block).FROM) {
                    fromExpr = BlocktoExpr(this._stack, block, blockIntputs(block).FROM);
                }
                if (blockIntputs(block).TO) {
                    toExpr = BlocktoExpr(this._stack, block, blockIntputs(block).TO);
                }
                if (blockIntputs(block).BY) {
                    byExpr = BlocktoExpr(this._stack, block, blockIntputs(block).BY);
                }
                let ast = new ForLoop();
                ast.setVarName(varName);
                ast.setFromExpr(fromExpr);
                ast.setToExpr(toExpr);
                ast.setByExpr(byExpr);
                ast.setStmt(stmt);
                ast.setBlockId(block.id);
                return ast;
            }
        },
        struct_set_field(block) {
            if (!(blockIntputs(block) && blockIntputs(block).DATA)) {
                this._stack.markError(block, '必须指定数据');
            }
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须指定值');
            }
            let stvalue = BlocktoExpr(this._stack, block, blockIntputs(block).DATA);
            let typefield = getFieldText(block.fields.FIELD);
            let idx = typefield.lastIndexOf('/');
            let fieldtype = typefield.substr(idx + 1);
            let idx1 = typefield.lastIndexOf(':');
            let type = typefield.substr(0, idx1);
            let fieldName = typefield.substr(idx1 + 1, idx - idx1 - 1);
            // let structDef = OpenBlock.BlocklyParser.getStructDefByName(type);

            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            let ast = new SetStructField(stvalue, type, fieldName, fieldtype, value);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_clone(block) {
            if (!(blockIntputs(block) && blockIntputs(block).DATA)) {
                this._stack.markError(block, '必须指定数据');
            }
            if (!(block.mutation && block.mutation.text)) {
                this._stack.markError(block, '必须指定类型');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).DATA);
            let type = decodeURI(block.mutation.text);
            let ast = new Clone(value, type);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_get_field(block) {
            let value;
            if (!(blockIntputs(block) && blockIntputs(block).DATA)) {
                this._stack.markError(block, '必须指定数据');
            } else {
                value = BlocktoExpr(this._stack, block, blockIntputs(block).DATA);
            }
            let typefield = getFieldText(block.fields.FIELD);
            let idx = typefield.lastIndexOf('/');
            let fieldtype = typefield.substr(idx + 1);
            let idx1 = typefield.lastIndexOf(':');
            let type = typefield.substr(0, idx1);
            let fieldName = typefield.substr(idx1 + 1, idx - idx1 - 1);
            // let structDef = OpenBlock.BlocklyParser.getStructDefByName(type);

            let ast = new GetStructField(value, type, fieldName, fieldtype);
            ast.setBlockId(block.id);
            return ast;
        },
        received_message_arg(block) {
            let ast = new ReceivedMessage(getFieldText(block.fields.TYPE));
            ast.setBlockId(block.id);
            return ast;
        },
        recived_message_arg(block) {
            // 早期拼写错误处理
            let ast = new ReceivedMessage(getFieldText(block.fields.TYPE));
            ast.setBlockId(block.id);
            return ast;
        },
        received_message_sender(block) {
            let ast = new SenderOfReceivedMessage();
            ast.setBlockId(block.id);
            return ast;
        },
        recived_message_sender(block) {
            // 早期拼写错误处理
            let ast = new SenderOfReceivedMessage();
            ast.setBlockId(block.id);
            return ast;
        },
        fsm_send_message(block) {
            if (!(blockIntputs(block) && blockIntputs(block).FSM)) {
                this._stack.markError(block, '必须指定发送目标');
            }
            if (getFieldText(block.fields.TITLE).length === 0) {
                this._stack.markError(block, '必须指定消息标题');
            }
            let ast = new FSMSendMessage();
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).FSM);
            ast.setTargetExpr(value);
            ast.setTitle(new TextConstExpr(getFieldText(block.fields.TITLE)));
            if (blockIntputs(block).ARG) {
                ast.setBodyExpr(BlocktoExpr(this._stack, block, blockIntputs(block).ARG));
            }
            ast.setBlockId(block.id);
            return ast;
        },
        fsm_group_message(block) {
            if (!(blockIntputs(block) && blockIntputs(block).FSMs)) {
                this._stack.markError(block, '必须指定发送目标');
            }
            if (getFieldText(block.fields.TITLE).length === 0) {
                this._stack.markError(block, '必须指定消息标题');
            }
            let ast = new FSMGroupMessage();
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).FSMs);
            ast.setTargetExpr(value);
            ast.setTitle(new TextConstExpr(getFieldText(block.fields.TITLE)));
            if (blockIntputs(block).ARG) {
                ast.setBodyExpr(BlocktoExpr(this._stack, block, blockIntputs(block).ARG));
            }
            ast.setBlockId(block.id);
            return ast;
        },

        fsm_send_dynamic_message(block) {
            if (!(blockIntputs(block) && blockIntputs(block).FSM)) {
                this._stack.markError(block, '必须指定发送目标');
            }
            if (!blockIntputs(block).TITLE) {
                this._stack.markError(block, '必须指定消息标题');
            }
            let ast = new FSMSendDynamicMessage();
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).FSM);
            ast.setTargetExpr(value);
            let tvalue = BlocktoExpr(this._stack, block, blockIntputs(block).TITLE);
            ast.setTitle(tvalue);
            if (blockIntputs(block).ARG) {
                ast.setBodyExpr(BlocktoExpr(this._stack, block, blockIntputs(block).ARG));
            }
            ast.setBlockId(block.id);
            return ast;
        },

        fsm_send_message_after_millisecond(block) {
            if (!(blockIntputs(block) && blockIntputs(block).FSM)) {
                this._stack.markError(block, '必须指定发送目标');
            }
            if (!blockIntputs(block).WAIT_MILLISECOND) {
                return OpenBlock.BlocklyParser.BlockToAST.fsm_send_message(block);
            }
            if (getFieldText(block.fields.TITLE).length === 0) {
                this._stack.markError(block, '必须指定消息标题');
            }
            let ast = new FSMSendMessageWait();
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).FSM);
            ast.setTargetExpr(value);
            ast.setTitle(new TextConstExpr(getFieldText(block.fields.TITLE)));
            ast.setWaitSecond(BlocktoExpr(this._stack, block, blockIntputs(block).WAIT_MILLISECOND));
            if (blockIntputs(block).ARG) {
                ast.setBodyExpr(BlocktoExpr(this._stack, block, blockIntputs(block).ARG));
            }
            ast.setBlockId(block.id);
            return ast;
        },
        fsm_send_interval_message_self(block) {
            if (getFieldText(block.fields.TITLE).length === 0) {
                this._stack.markError(block, '必须指定消息标题');
            }
            let ast = new FSMSendMessageIntervalToSelf();
            ast.setTitle(new TextConstExpr(getFieldText(block.fields.TITLE)));
            ast.setMillisecond(BlocktoExpr(this._stack, block, blockIntputs(block).INTERVAL_MILLISECOND));
            ast.setBlockId(block.id);
            return ast;
        },
        fsm_broadcast_message_after_millisecond(block) {
            if (!(blockIntputs(block) && blockIntputs(block).WAIT_MILLISECOND)) {
                return OpenBlock.BlocklyParser.BlockToAST.fsm_broadcast_message(block);
            }
            if (getFieldText(block.fields.TITLE).length === 0) {
                this._stack.markError(block, '必须指定消息标题');
            }
            let ast = new FSMBroadcastMessageWait();
            ast.setTitle(new TextConstExpr(getFieldText(block.fields.TITLE)));
            ast.setMillisecond(BlocktoExpr(this._stack, block, blockIntputs(block).WAIT_MILLISECOND));
            if (blockIntputs(block).ARG) {
                ast.setBodyExpr(BlocktoExpr(this._stack, block, blockIntputs(block).ARG));
            }
            if (typeof (block.fields.SEND_SELF) == 'boolean') {
                ast.sendToSelf = block.fields.SEND_SELF;
            } else {
                ast.sendToSelf = block.fields.SEND_SELF ? getFieldText(block.fields.SEND_SELF) === 'TRUE' : false;
            }
            ast.setBlockId(block.id);
            return ast;
        },
        fsm_broadcast_message(block) {
            if (getFieldText(block.fields.TITLE).length === 0) {
                this._stack.markError(block, '必须指定消息标题');
            }
            let ast = new FSMBroadcastMessage();
            ast.setTitle(new TextConstExpr(getFieldText(block.fields.TITLE)));
            if (blockIntputs(block) && blockIntputs(block).ARG) {
                ast.setBodyExpr(BlocktoExpr(this._stack, block, blockIntputs(block).ARG));
            }
            if (typeof (block.fields.SEND_SELF) == 'boolean') {
                ast.sendToSelf = block.fields.SEND_SELF;
            } else {
                ast.sendToSelf = block.fields.SEND_SELF ? getFieldText(block.fields.SEND_SELF) === 'TRUE' : false;
            }
            ast.setBlockId(block.id);
            return ast;
        },
        struct_load_from_dataset(block) {
            if (!(blockIntputs(block) && blockIntputs(block).ID)) {
                this._stack.markError(block, '必须指定ID');
            }
            let methodName = 'Struct_loadStructFromDataset';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let id = BlocktoExpr(this._stack, block, blockIntputs(block).ID, "必须提供值");
            let typename = getFieldText(block.fields.TYPE);
            let textExpr = new TextConstExpr(typename);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('type', textExpr);
            ast.setArg('id', id);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_list_concat(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAINLIST)) {
                this._stack.markError(block, '必须指定主列表');
            }
            if (!(blockIntputs(block) && blockIntputs(block).LIST)) {
                this._stack.markError(block, '必须指定列表');
            }
            let methodName = 'Struct_concat_list';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let MAINLIST = BlocktoExpr(this._stack, block, blockIntputs(block).MAINLIST, "必须提供值");
            let LIST = BlocktoExpr(this._stack, block, blockIntputs(block).LIST, "必须提供值");
            let ast = new VoidNativeCall();
            ast.setFunc(func);
            ast.setArg('mainList', MAINLIST);
            ast.setArg('list', LIST);
            ast.setBlockId(block.id);
            return ast;
        },
        math_text_to_integer(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TEXT)) {
                this._stack.markError(block, '必须指定文本内容');
            }
            let methodName = 'math_text_to_integer';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let text = BlocktoExpr(this._stack, block, blockIntputs(block).TEXT, "必须提供值");
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('text', text);
            ast.setBlockId(block.id);
            return ast;
        },
        math_text_to_number(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TEXT)) {
                this._stack.markError(block, '必须指定文本内容');
            }
            let methodName = 'math_text_to_number';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let text = BlocktoExpr(this._stack, block, blockIntputs(block).TEXT, "必须提供值");
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('text', text);
            ast.setBlockId(block.id);
            return ast;
        },
        struct(block) {
            let name = getFieldText(block.fields.NAME);
            if (!name || name.length === 0) {
                this._stack.markError(block, '必须设置名称');
            }
            let ast = new StructDef();
            ast.setName(name);
            if (blockStatements(block) && blockStatements(block).FIELDS) {
                for (let field = blockStatements(block).FIELDS; field; field = field.next) {
                    ast.addField(getBlockAST(field));
                    if (field.block && !field.next) {
                        field = field.block;
                    }
                }
            }
            ast.setBlockId(block.id);
            return ast;
        },
        struct_field(block) {
            let name = getFieldText(block.fields.NAME);
            let ast = new StructField();
            if (!(blockIntputs(block) && blockIntputs(block).TYPE)) {
                this._stack.markError(block, '必须指定类型');
            }
            let type = getBlockAST(blockIntputs(block).TYPE);
            ast.setType(type);
            ast.setName(name);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_structs(block) {
            if (!(block.fields && block.fields.TYPE)) {
                this._stack.markError(block, '必须指定类型');
            }
            let typename = getFieldText(block.fields.TYPE);
            if (typename.length <= 0) {
                this._stack.markError(block, '必须指定类型');
            }
            let ast = new StructFieldTypeStruct();
            ast.setName(typename);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_native(block) {
            if (!(block.fields && block.fields.TYPE)) {
                this._stack.markError(block, '必须指定类型');
            }
            let typename = getFieldText(block.fields.TYPE);
            if (typename.length <= 0) {
                this._stack.markError(block, '必须指定类型');
            }
            let ast = new StructFieldTypeNative();
            ast.setName(typename);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_list(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TYPE)) {
                this._stack.markError(block, '必须指定元素类型');
            }
            let ast = new StructFieldTypeList();
            ast.setElementType(getBlockAST(blockIntputs(block).TYPE));
            ast.setBlockId(block.id);
            return ast;
        },
        struct_string_map(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TYPE)) {
                this._stack.markError(block, '必须指定元素类型');
            }
            let ast = new StructFieldTypeStringMap();
            ast.setElementType(getBlockAST(blockIntputs(block).TYPE));
            ast.setBlockId(block.id);
            return ast;
        },
        struct_integer_map(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TYPE)) {
                this._stack.markError(block, '必须指定元素类型');
            }
            let ast = new StructFieldTypeIntegerMap();
            ast.setElementType(getBlockAST(blockIntputs(block).TYPE));
            ast.setBlockId(block.id);
            return ast;
        },
        struct_base_type(block) {
            if (!(block.fields && block.fields.TYPE)) {
                this._stack.markError(block, '必须指定类型');
            }
            let typename = getFieldText(block.fields.TYPE);
            if (typename.length <= 0) {
                this._stack.markError(block, '必须指定类型');
            }
            let ast = new StructFieldType();
            ast.setName(typename);
            ast.setBlockId(block.id);
            return ast;
        },
        fsm_create(block) {
            let fsmtype = getFieldText(block.fields.FSM);
            let textExpr = new TextConstExpr(fsmtype);
            let createFSM = new CreateFSM(textExpr);
            createFSM.setBlockId(block.id);
            return createFSM;
        },
        find_fsm_by_type(block) {
            if (!(block.fields && block.fields.FSM)) {
                this._stack.markError(block, '必须指定名称');
            }
            let methodName = 'FSM_findFsmByType';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let fsmtype = getFieldText(block.fields.FSM);
            let textExpr = new TextConstExpr(fsmtype);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('typeName', textExpr);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_count_in_dataset(block) {
            let methodName = 'Struct_countInDataset';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let typename = getFieldText(block.fields.TYPE);
            let textExpr = new TextConstExpr(typename);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('type', textExpr);
            ast.setBlockId(block.id);
            return ast;
        },
        fsm_variables_get(block) {
            let variableName = getFieldText(block.fields.VAR);
            let ast = new GetFSMVariableValue();
            ast.setName(variableName);
            ast.setBlockId(block.id);
            return ast;
        },
        fsm_variables_set(block) {
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供值');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE, "必须提供值");
            let variableName = getFieldText(block.fields.VAR);
            let ast = new SetFSMVariableValue();
            ast.setName(variableName);
            ast.setValue(value);
            ast.setBlockId(block.id);
            return ast;
        },
        state_variables_get(block) {
            let variableName = getFieldText(block.fields.VAR);
            let ast = new GetStateVariableValue();
            ast.setName(variableName);
            ast.setBlockId(block.id);
            return ast;
        },
        state_variables_set(block) {
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供值');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE, "必须提供值");
            let variableName = getFieldText(block.fields.VAR);
            let ast = new SetStateVariableValue();
            ast.setName(variableName);
            ast.setValue(value);
            ast.setBlockId(block.id);
            return ast;
        },
        change_state(block) {
            let ast = new ChangeState();
            ast.setTargetStateName(getFieldText(block.fields.VALUE));
            ast.setBlockId(block.id);
            return ast;
        },
        push_state(block) {
            let ast = new PushState();
            ast.setTargetStateName(getFieldText(block.fields.VALUE));
            ast.setBlockId(block.id);
            return ast;
        },
        pop_state(block) {
            let ast = new PopState();
            ast.setBlockId(block.id);
            return ast;
        },
        destroy_fsm(block) {
            let ast = new DFSM();
            ast.setBlockId(block.id);
            return ast;
        },
        on_event(block) {
            let ast = new EventHandlerDef();
            this._stack?.push(block);
            this._stack?.setCurrentAST(ast);
            ast.setEventName(block.mutation.eventname);
            ast.setBody(BlocktoStatementDef(block.next));
            ast.setBlockId(block.id);
            this._stack?.pop();
            return ast;
        },
        on_message(block) {
            let title = getFieldText(block.fields.VALUE);
            if (!OpenBlock.Utils.isMessageTitle(title)) {
                this._stack.markError(block, OpenBlock.i('消息标题不合法'));
            }
            let ast = new MessageHandlerDef();
            this._stack?.push(block);
            this._stack?.setCurrentAST(ast);
            ast.setTitle(title);
            ast.setBody(BlocktoStatementDef(block.next));
            ast.setBlockId(block.id);
            this._stack?.pop();
            return ast;
        },
        on_message_struct(block) {
            let title = getFieldText(block.fields.VALUE);
            if (!OpenBlock.Utils.isMessageTitle(title)) {
                this._stack.markError(block, OpenBlock.i('消息标题不合法'));
            }
            let ast = new MessageHandlerDef();
            this._stack?.push(block);
            this._stack?.setCurrentAST(ast);
            ast.setTitle(title);
            ast.setMessageType((block.inputs ? block.inputs.TYPE.block.AST(block.inputs.TYPE.block).toCodeText() : block.fields.TYPE.text));
            ast.setBody(BlocktoStatementDef(block.next));
            ast.setBlockId(block.id);
            this._stack?.pop();
            return ast;
        },
        on_message_primary(block) {
            let title = getFieldText(block.fields.VALUE);
            if (!OpenBlock.Utils.isMessageTitle(title)) {
                this._stack.markError(block, OpenBlock.i('消息标题不合法'));
            }
            let ast = new MessageHandlerDef();
            this._stack?.push(block);
            this._stack?.setCurrentAST(ast);
            ast.setTitle(title);
            ast.setMessageType(getFieldText(block.fields.TYPE));
            ast.setBody(BlocktoStatementDef(block.next));
            ast.setBlockId(block.id);
            this._stack?.pop();
            return ast;
        },
        on_message_with_arg(block) {
            let title = getFieldText(block.fields.VALUE);
            if (!OpenBlock.Utils.isMessageTitle(title)) {
                this._stack.markError(block, OpenBlock.i('消息标题不合法'));
            }
            let ast = new MessageHandlerDef();
            this._stack?.push(block);
            this._stack?.setCurrentAST(ast);
            ast.setTitle(title);
            ast.setMessageType(getFieldText(block.fields.TYPE));
            ast.setBody(BlocktoStatementDef(block.next));
            ast.setBlockId(block.id);
            this._stack?.pop();
            return ast;
        },
        logic_compare(block) {
            let op = getFieldText(block.fields.OP);
            let ast = new Compare();
            ast.setOP(op);
            let l = BlocktoExpr(this._stack, block, blockIntputs(block).A, "必须提供值");
            let r = BlocktoExpr(this._stack, block, blockIntputs(block).B, "必须提供值");

            ast.setLeft(l);
            ast.setRight(r);
            ast.setBlockId(block.id);
            return ast;
        },
        math_arithmetic(block) {
            let op = getFieldText(block.fields.OP);
            let ast = new ARITH();
            ast.setOP(op);
            ast.setLeft(BlocktoExpr(this._stack, block, blockIntputs(block).A, "必须提供值"));
            ast.setRight(BlocktoExpr(this._stack, block, blockIntputs(block).B, "必须提供值"));
            ast.setBlockId(block.id);
            return ast;
        },
        math_binary_bit_operator(block) {
            let op = getFieldText(block.fields.OP);
            let ast = new ARITH();
            ast.setOP(op);
            ast.setLeft(BlocktoExpr(this._stack, block, blockIntputs(block).A, "必须提供值"));
            ast.setRight(BlocktoExpr(this._stack, block, blockIntputs(block).B, "必须提供值"));
            ast.setBlockId(block.id);
            return ast;
        },
        math_bit_operator_NOT(block) {
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).A);
            let ast = new MathSingle();
            ast.setOP('~');
            ast.setValue(value);
            ast.setBlockId(block.id);
            return ast;
        },
        ub_math_arithmetic(block) {
            let op = getFieldText(block.fields.OP);
            let ast = new ARITH();
            ast.setOP(op);
            ast.setLeft(BlocktoExpr(this._stack, block, blockIntputs(block).A, "必须提供值"));
            ast.setRight(BlocktoExpr(this._stack, block, blockIntputs(block).B, "必须提供值"));
            ast.setBlockId(block.id);
            return ast;
        },
        math_number(block) {
            let ast = new FloatConstExpr();
            let txt = typeof (block.fields.NUM) == 'number' ? block.fields.NUM : getFieldText(block.fields.NUM);
            ast.number = parseFloat(txt);
            ast.setBlockId(block.id);
            return ast;
        },
        math_integer(block) {
            let ast = new IntegerConstExpr();
            let txt = typeof (block.fields.NUM) == 'number' ? block.fields.NUM : getFieldText(block.fields.NUM);
            ast.number = parseInt(txt);
            ast.setBlockId(block.id);
            return ast;
        },
        text(m) {
            let ast = new TextConstExpr();
            ast.setText(getFieldText(m.fields.TEXT));
            ast.setBlockId(m.id);
            return ast;
        },
        text_multiline(b) {
            let ast = new TextConstExpr();
            let str = getFieldText(b.fields.TEXT);
            // let html = $("<div/>").html(str).text();
            let div = document.createElement('div');
            div.innerHTML = str;
            let html = div.innerText;
            ast.setBlockId(b.id);
            ast.setText(html);
            return ast;
        },
        text_print(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TEXT)) {
                this._stack.markError(block, '必须提供值');
            }
            let ast = new LOG();
            ast.expr = BlocktoExpr(this._stack, block, blockIntputs(block).TEXT, "必须提供值");
            ast.setBlockId(block.id);
            return ast;
        },
        colour_picker(block) {
            let colorValue = getFieldText(block.fields.COLOUR);
            colorValue = colorValue.substr(1);
            colorValue = colorValue + "FF";
            let intValue = parseInt(colorValue, 16)
            let ast = new IntegerConstExpr();
            ast.astType = 'Colour';
            ast.setBlockId(block.id);
            ast.number = intValue;
            return ast;
        },
        colour_hsv(block) {
            let colorValue = getFieldText(block.fields.COLOUR);
            colorValue = colorValue.substr(1);
            colorValue = colorValue + "FF";
            let intValue = parseInt(colorValue, 16)
            let ast = new IntegerConstExpr();
            ast.astType = 'Colour';
            ast.setBlockId(block.id);
            ast.number = intValue;
            return ast;
        },
        struct_map_get_value_of_key(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供字符串映射');
            }
            if (!(blockIntputs(block) && blockIntputs(block).KEY)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let key = BlocktoExpr(this._stack, block, blockIntputs(block).KEY);
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new ValueOfMap(map, key);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_imap_get_value_of_key(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供整数映射');
            }
            if (!(blockIntputs(block) && blockIntputs(block).KEY)) {
                this._stack.markError(block, '必须提供整数');
            }
            let key = BlocktoExpr(this._stack, block, blockIntputs(block).KEY);
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new ValueOfIMap(map, key);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_container_size(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供映射');
            }
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new SizeOfMap(map);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_map_remove_value_of_key(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供字符串映射');
            }
            if (!(blockIntputs(block) && blockIntputs(block).KEY)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let key = BlocktoExpr(this._stack, block, blockIntputs(block).KEY);
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new RKOM(map, key);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_smap_exist(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供字符串映射');
            }
            if (!(blockIntputs(block) && blockIntputs(block).KEY)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let key = BlocktoExpr(this._stack, block, blockIntputs(block).KEY);
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new SME(map, key);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_imap_exist(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供字符串映射');
            }
            if (!(blockIntputs(block) && blockIntputs(block).KEY)) {
                this._stack.markError(block, '必须提供整数');
            }
            let key = BlocktoExpr(this._stack, block, blockIntputs(block).KEY);
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new IME(map, key);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_smap_all_key(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供字符串映射');
            }
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new SMA(map);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_imap_all_key(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供整数映射');
            }
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new IMA(map);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_imap_delete_value_of_key(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供整数映射');
            }
            if (!(blockIntputs(block) && blockIntputs(block).KEY)) {
                this._stack.markError(block, '必须提供整数');
            }
            let key = BlocktoExpr(this._stack, block, blockIntputs(block).KEY);
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new RKOIM(map, key);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_map_set_value_of_key(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供字符串映射');
            }
            if (!(blockIntputs(block) && blockIntputs(block).KEY)) {
                this._stack.markError(block, '必须提供字符串');
            }
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供值');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            let key = BlocktoExpr(this._stack, block, blockIntputs(block).KEY);
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new STKV(map, key, value);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_imap_set_value_of_key(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MAP)) {
                this._stack.markError(block, '必须提供整数映射');
            }
            if (!(blockIntputs(block) && blockIntputs(block).KEY)) {
                this._stack.markError(block, '必须提供整数');
            }
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供值');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            let key = BlocktoExpr(this._stack, block, blockIntputs(block).KEY);
            let map = BlocktoExpr(this._stack, block, blockIntputs(block).MAP);
            let ast = new STIKV(map, key, value);
            ast.setBlockId(block.id);
            return ast;
        },
        text_length(block) {
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            let methodName = 'Text_Length';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('str', value);
            ast.setBlockId(block.id);
            return ast;
        },
        text_isEmpty(block) {
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            let methodName = 'Text_IsEmpty';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('str', value);
            ast.setBlockId(block.id);
            return ast;
        },
        text_indexOf(block) {
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            if (!(blockIntputs(block) && blockIntputs(block).FIND)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let FIND = BlocktoExpr(this._stack, block, blockIntputs(block).FIND);
            if (!(block.fields && block.fields.END)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let END = new IntegerConstExpr();
            END.number = getFieldText(block.fields.END) === 'FIRST' ? 1 : 0;
            let methodName = 'Text_IndexOf';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('str', value);
            ast.setArg('sub', FIND);
            ast.setArg('forward', END);
            ast.setBlockId(block.id);
            return ast;
        },
        text_indexOfFrom(block) {
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            if (!(blockIntputs(block) && blockIntputs(block).FIND)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let FIND = BlocktoExpr(this._stack, block, blockIntputs(block).FIND);
            if (!(blockIntputs(block) && blockIntputs(block).FROM)) {
                this._stack.markError(block, '必须提起始位置');
            }
            let FROM = BlocktoExpr(this._stack, block, blockIntputs(block).FROM);
            let methodName = 'Text_IndexOfFrom';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('str', value);
            ast.setArg('sub', FIND);
            ast.setArg('from', FROM);
            ast.setBlockId(block.id);
            return ast;
        },
        text_charAt(block) {
            if (!(block.fields && block.fields.WHERE)) {
                this._stack.markError(block, '必须提搜索方式');
            }

            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            let AT;
            switch (getFieldText(block.fields.WHERE)) {
                case 'FROM_START':
                    let s_AT = BlocktoExpr(this._stack, block, blockIntputs(block).AT);
                    if (!(s_AT instanceof IntegerExpr)) {
                        let s__AT = new MathSingle();
                        s__AT.setOP('ROUNDDOWN');
                        s__AT.setValue(s_AT);
                        AT = new F2I(s__AT);
                    } else {
                        AT = s_AT;
                    }
                    break;
                case 'FROM_END':
                    let e_AT = BlocktoExpr(this._stack, block, blockIntputs(block).AT);
                    let e__AT = new MathSingle();
                    e__AT.setOP('NEG');
                    e__AT.setValue(e_AT);
                    AT = new F2I(e__AT);
                    break;
                case 'FIRST':
                    AT = new IntegerConstExpr();
                    AT.number = 1;
                    break;
                case 'LAST':
                    AT = new IntegerConstExpr();
                    AT.number = -1;
                    break;
                case 'RANDOM':
                    AT = new RandomInt();
                    AT.From = new FloatConstExpr();
                    AT.From.number = 1;
                    let methodName = 'Text_Length';
                    let func = OpenBlock.Env.findBuildInFunction(methodName);
                    let l = new ValueNativeCall();
                    l.setFunc(func);
                    l.setArg('str', value);
                    AT.To = new I2F(l);
                    break;
                default:
                    this._stack.markError(block, '未知操作 ' + getFieldText(block.fields.WHERE));
            }
            let methodName = 'Text_CharAt';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('str', value);
            ast.setArg('at', AT);
            ast.setBlockId(block.id);
            return ast;
        },
        text_getSubstring(block) {
            if (!(blockIntputs(block) && blockIntputs(block).STRING)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let str = BlocktoExpr(this._stack, block, blockIntputs(block).STRING);
            let at = [];
            for (let i = 0; i <= 1; i++) {
                let j = i + 1;
                let where = getFieldText(block.fields['WHERE' + j]);
                switch (where) {
                    case 'FROM_START':
                        let f_at = BlocktoExpr(this._stack, block, blockIntputs(block)['AT' + j]);
                        if (!(f_at instanceof IntegerExpr)) {
                            let f__AT = new MathSingle();
                            f__AT.setOP('ROUNDDOWN');
                            f__AT.setValue(f_at);
                            at[i] = new F2I(f__AT);
                        } else {
                            at[i] = f_at;
                        }
                        break;
                    case 'FROM_END':
                        let e_AT = BlocktoExpr(this._stack, block, blockIntputs(block)['AT' + j]);
                        let e__AT = new MathSingle();
                        e__AT.setOP('NEG');
                        e__AT.setValue(e_AT);
                        at[i] = new F2I(e__AT);
                        break;
                    case 'FIRST':
                        at[i] = new IntegerConstExpr();
                        at[i].number = 1;
                        break;
                    case 'LAST':
                        at[i] = new IntegerConstExpr();
                        at[i].number = -1;
                        break;
                    default:
                        this._stack.markError(block, '不支持的操作 ' + where);
                }
            }
            let methodName = 'Text_GetSubstring';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('str', str);
            ast.setArg('from', at[0]);
            ast.setArg('to', at[1]);
            ast.setBlockId(block.id);
            return ast;
        },
        text_changeCase(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TEXT)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let str = BlocktoExpr(this._stack, block, blockIntputs(block).TEXT);
            let _case = getFieldText(block.fields.CASE);
            let methodName;
            switch (_case) {
                case 'UPPERCASE':
                    methodName = "Text_ToUpperCase";
                    break;
                case 'LOWERCASE':
                    methodName = "Text_ToLowerCase";
                    break;
                case 'TITLECASE':
                    methodName = "Text_ToTitleCase";
                    break;
                default:
                    this._stack.markError(block, '不支持的操作 ' + _case);
            }
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('str', str);
            ast.setBlockId(block.id);
            return ast;
        },
        text_count(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TEXT)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let str = BlocktoExpr(this._stack, block, blockIntputs(block).TEXT);
            if (!(blockIntputs(block) && blockIntputs(block).SUB)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let sub = BlocktoExpr(this._stack, block, blockIntputs(block).SUB);
            let methodName = 'Text_Count';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('str', str);
            ast.setArg('sub', sub);
            ast.setBlockId(block.id);
            return ast;
        },
        text_replace(block) {
            if (!(blockIntputs(block) && blockIntputs(block).FROM)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let FROM = BlocktoExpr(this._stack, block, blockIntputs(block).FROM);
            if (!(blockIntputs(block) && blockIntputs(block).TO)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let TO = BlocktoExpr(this._stack, block, blockIntputs(block).TO);
            if (!(blockIntputs(block) && blockIntputs(block).TEXT)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let TEXT = BlocktoExpr(this._stack, block, blockIntputs(block).TEXT);

            let methodName = 'Text_Replace';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('from', FROM);
            ast.setArg('to', TO);
            ast.setArg('text', TEXT);
            ast.setBlockId(block.id);
            return ast;
        },
        text_reverse(block) {
            if (!(blockIntputs(block) && blockIntputs(block).TEXT)) {
                this._stack.markError(block, '必须提供字符串');
            }
            let TEXT = BlocktoExpr(this._stack, block, blockIntputs(block).TEXT);
            let methodName = 'Text_Reverse';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setArg('str', TEXT);
            ast.setBlockId(block.id);
            return ast;
        },
        integer_to_colour(block) {
            if (!(blockIntputs(block) && blockIntputs(block).value)) {
                this._stack.markError(block, '必须提供参数');
            }
            let v = BlocktoExpr(this._stack, block, blockIntputs(block).value);
            return v;
        },
        colour_to_integer(block) {
            if (!(blockIntputs(block) && blockIntputs(block).value)) {
                this._stack.markError(block, '必须提供参数');
            }
            let v = BlocktoExpr(this._stack, block, blockIntputs(block).value);
            return v;
        },
        colour_rgb(block) {
            if (!(blockIntputs(block) && blockIntputs(block).RED)) {
                this._stack.markError(block, '必须提供颜色');
            }
            let R1 = BlocktoExpr(this._stack, block, blockIntputs(block).RED);
            if (!(blockIntputs(block) && blockIntputs(block).GREEN)) {
                this._stack.markError(block, '必须提供颜色');
            }
            let G1 = BlocktoExpr(this._stack, block, blockIntputs(block).GREEN);
            if (!(blockIntputs(block) && blockIntputs(block).BLUE)) {
                this._stack.markError(block, '必须提供颜色');
            }
            let B1 = BlocktoExpr(this._stack, block, blockIntputs(block).BLUE);
            let R24 = new IntegerConstExpr();
            R24.number = 1 << 24;

            let R16 = new IntegerConstExpr();
            R16.number = 1 << 16;

            let R8 = new IntegerConstExpr();
            R8.number = 1 << 8;

            let R = new ARITH();
            R.setOP('MULTIPLY');
            R.setLeft(R1);
            R.setRight(R24);

            let G = new ARITH();
            G.setOP('MULTIPLY');
            G.setLeft(G1);
            G.setRight(R16);

            let B = new ARITH();
            B.setOP('MULTIPLY');
            B.setLeft(B1);
            B.setRight(R8);

            let A1 = new ARITH();
            A1.setOP('ADD');
            A1.setLeft(R);
            A1.setRight(G);

            let A2 = new ARITH();
            A2.setOP('ADD');
            A2.setLeft(A1);
            A2.setRight(B);

            let I0xFF = new IntegerConstExpr();
            I0xFF.number = 0xFF;

            let A3 = new ARITH();
            A3.setOP('ADD');
            A3.setLeft(A2);
            A3.setRight(I0xFF);

            A3.setBlockId(block.id);
            return A3;
        },
        colour_blend(block) {
            if (!(blockIntputs(block) && blockIntputs(block).COLOUR1)) {
                this._stack.markError(block, '必须提供颜色');
            }
            let C1 = new FixRegister(BlocktoExpr(this._stack, block, blockIntputs(block).COLOUR1));
            if (!(blockIntputs(block) && blockIntputs(block).COLOUR2)) {
                this._stack.markError(block, '必须提供颜色');
            }
            let C2 = new FixRegister(BlocktoExpr(this._stack, block, blockIntputs(block).COLOUR2));
            if (!(blockIntputs(block) && blockIntputs(block).RATIO)) {
                this._stack.markError(block, '必须提供颜色');
            }
            let RATIO2 = BlocktoExpr(this._stack, block, blockIntputs(block).RATIO);
            let solidifyRATIO2 = new FixRegister(RATIO2);
            let RATIO1 = new ARITH();
            RATIO1.setOP('MINUS');
            RATIO1.setLeft(new IntegerConstExpr(1));
            RATIO1.setRight(solidifyRATIO2);
            let solidifyRATIO1 = new FixRegister(RATIO1);

            let R1 = new SHL(new BitAnd(new IntegerConstExpr(0xFF000000), C1), new IntegerConstExpr(-24));
            let G1 = new SHL(new BitAnd(new IntegerConstExpr(0xFF0000), C1), new IntegerConstExpr(-16));
            let B1 = new SHL(new BitAnd(new IntegerConstExpr(0xFF00), C1), new IntegerConstExpr(-8));
            let T1 = new BitAnd(C1.unfix(), new IntegerConstExpr(0xFF));
            let R2 = new SHL(new BitAnd(new IntegerConstExpr(0xFF000000), C2), new IntegerConstExpr(-24));
            let G2 = new SHL(new BitAnd(new IntegerConstExpr(0xFF0000), C2), new IntegerConstExpr(-16));
            let B2 = new SHL(new BitAnd(new IntegerConstExpr(0xFF00), C2), new IntegerConstExpr(-8));
            let T2 = new BitAnd(C2.unfix(), new IntegerConstExpr(0xFF));

            let SR1 = new ARITH();
            SR1.setOP('MULTIPLY');
            SR1.setLeft(R1);
            SR1.setRight(solidifyRATIO1);
            let SR2 = new ARITH();
            SR2.setOP('MULTIPLY');
            SR2.setLeft(R2);
            SR2.setRight(solidifyRATIO2);
            let RR = new ARITH();
            RR.setOP('ADD');
            RR.setLeft(SR1);
            RR.setRight(SR2);
            RR = new F2I(RR);

            let SG1 = new ARITH();
            SG1.setOP('MULTIPLY');
            SG1.setLeft(G1);
            SG1.setRight(solidifyRATIO1);
            let SG2 = new ARITH();
            SG2.setOP('MULTIPLY');
            SG2.setLeft(G2);
            SG2.setRight(solidifyRATIO2);
            let RG = new ARITH();
            RG.setOP('ADD');
            RG.setLeft(SG1);
            RG.setRight(SG2);
            RG = new F2I(RG);

            let SB1 = new ARITH();
            SB1.setOP('MULTIPLY');
            SB1.setLeft(B1);
            SB1.setRight(solidifyRATIO1);
            let SB2 = new ARITH();
            SB2.setOP('MULTIPLY');
            SB2.setLeft(B2);
            SB2.setRight(solidifyRATIO2);
            let RB = new ARITH();
            RB.setOP('ADD');
            RB.setLeft(SB1);
            RB.setRight(SB2);
            RB = new F2I(RB);

            let ST1 = new ARITH();
            ST1.setOP('MULTIPLY');
            ST1.setLeft(T1);
            ST1.setRight(solidifyRATIO1.unfix());
            let ST2 = new ARITH();
            ST2.setOP('MULTIPLY');
            ST2.setLeft(T2);
            ST2.setRight(solidifyRATIO2.unfix());
            let RT = new ARITH();
            RT.setOP('ADD');
            RT.setLeft(ST1);
            RT.setRight(ST2);
            RT = new F2I(RT);


            let SR = new SHL(new BitAnd(RR, new IntegerConstExpr(0xFF)), new IntegerConstExpr(24));
            let SG = new SHL(new BitAnd(RG, new IntegerConstExpr(0xFF)), new IntegerConstExpr(16));
            let SB = new SHL(new BitAnd(RB, new IntegerConstExpr(0xFF)), new IntegerConstExpr(8));
            let ST = new BitAnd(RT, new IntegerConstExpr(0xFF));

            let fRG = new ARITH();
            fRG.setOP('ADD');
            fRG.setLeft(SR);
            fRG.setRight(SG);

            let RGB = new ARITH();
            RGB.setOP('ADD');
            RGB.setLeft(fRG);
            RGB.setRight(SB);

            let RGBT = new ARITH();
            RGBT.setOP('ADD');
            RGBT.setLeft(RGB);
            RGBT.setRight(ST);

            RGBT.setBlockId(block.id);
            return RGBT;
        },
        colour_random(block) {
            let F0xFF = new FloatConstExpr();
            F0xFF.number = 0xFF;

            let R24 = new IntegerConstExpr();
            R24.number = 1 << 24;

            let R16 = new IntegerConstExpr();
            R16.number = 1 << 16;

            let R8 = new IntegerConstExpr();
            R8.number = 1 << 8;

            let randInt = new RandomInt();
            randInt.From = new FloatConstExpr();
            randInt.From.number = 0;
            randInt.To = F0xFF;

            let R = new ARITH();
            R.setOP('MULTIPLY');
            R.setLeft(randInt);
            R.setRight(R24);

            let G = new ARITH();
            G.setOP('MULTIPLY');
            G.setLeft(randInt);
            G.setRight(R16);

            let B = new ARITH();
            B.setOP('MULTIPLY');
            B.setLeft(randInt);
            B.setRight(R8);

            let A1 = new ARITH();
            A1.setOP('ADD');
            A1.setLeft(R);
            A1.setRight(G);

            let A2 = new ARITH();
            A2.setOP('ADD');
            A2.setLeft(A1);
            A2.setRight(B);

            let I0xFF = new IntegerConstExpr();
            I0xFF.number = 0xFF;

            let A3 = new ARITH();
            A3.setOP('ADD');
            A3.setLeft(A2);
            A3.setRight(I0xFF);

            A3.setBlockId(block.id);
            return A3;
        },
        logic_operation(block) {
            if (!(blockIntputs(block) && blockIntputs(block).A)) {
                this._stack.markError(block, '必须提供条件');
            }
            let A = (BlocktoExpr(this._stack, block, blockIntputs(block).A));
            if (!(blockIntputs(block) && blockIntputs(block).B)) {
                this._stack.markError(block, '必须提供条件');
            }
            let B = (BlocktoExpr(this._stack, block, blockIntputs(block).B));
            if (getFieldText(block.fields.OP) === 'AND') {
                let ast = new LogicAnd(A, B);
                ast.setBlockId(block.id);
                return ast;
            } else {
                let ast = new LogicOr(A, B);
                ast.setBlockId(block.id);
                return ast;
            }
        },
        logic_negate(block) {
            if (!(blockIntputs(block) && blockIntputs(block).BOOL)) {
                this._stack.markError(block, '必须提供条件');
            }
            let A = (BlocktoExpr(this._stack, block, blockIntputs(block).BOOL));
            let ast = new LogicNot(A);
            ast.setBlockId(block.id);
            return ast;
        },
        math_constrain(block) {
            let VALUE = (BlocktoExpr2(this._stack, block, blockIntputs(block), 'VALUE'));
            let LOW = (BlocktoExpr2(this._stack, block, blockIntputs(block), 'LOW'));
            let HIGH = (BlocktoExpr2(this._stack, block, blockIntputs(block), 'HIGH'));
            let c = new ConstrainNumber();
            c.setValue(VALUE);
            c.setMax(HIGH);
            c.setMin(LOW);
            c.setBlockId(block.id);
            return c;
        },
        logic_ternary(block) {
            let IF = BlocktoExpr2(this._stack, block, blockIntputs(block), 'IF');
            let THEN = BlocktoExpr2(this._stack, block, blockIntputs(block), 'THEN');
            let ELSE = BlocktoExpr2(this._stack, block, blockIntputs(block), 'ELSE');
            let ast = new Conditional(IF, THEN, ELSE);
            ast.setBlockId(block.id);
            return ast;
        },
        fsm_provider(block) {
            let fsmtype = getFieldText(block.fields.FSM);
            let textExpr = new TextConstExpr(fsmtype);
            textExpr.setBlockId(block.id);
            return textExpr;
        },
        empty_provider(block) {
            let mutation = JSON.parse(block.mutation.text);
            let value = getFieldText(block.fields.VALUE);
            let textExpr;
            if (mutation.eleType == 'ref') {
                textExpr = new EnvRef(value, mutation.checkType);
            } else {
                switch (mutation.checkType) {
                    case 'String':
                        textExpr = new TextConstExpr(value);
                        break;
                    case 'Number':
                        textExpr = new FloatConstExpr(Number(value));
                        break;
                    case 'Integer':
                        textExpr = new IntegerConstExpr(Math.floor(Number(value)));
                        break;
                    default:
                        textExpr = new TextConstExpr(value);
                        break;
                }
            }
            textExpr.setBlockId(block.id);
            return textExpr;
        },
        text_comment(block) {
            let ast = new Comment(getFieldText(block.fields.TEXT));
            ast.setBlockId(block.id);
            return ast;
        },
        colour_comment(block) {
            let ast = new Comment(getFieldText(block.fields.TEXT));
            ast.setBlockId(block.id);
            return ast;
        },
        struct_new(block) {
            let t = getFieldText(block.fields.TYPE);
            if (t.length == 0) {
                this._stack.markError(block, OpenBlock.i('需要设置类型'));
            }
            let ast = new NewStruct(t);
            ast.setBlockId(block.id);
            return ast;
        },
        text_key_value(m) {
            let ast = new TextConstExpr();
            ast.setText(getFieldText(m.fields.VALUE));
            ast.setBlockId(m.id);
            return ast;
        },
        struct_new_collection(block) {
            let ast;
            switch (getFieldText(block.fields.TYPE)) {
                case 'list':
                    ast = new CreateList();
                    break;
                case 'string_map':
                    ast = new CreateStringMap();
                    break;
                case 'integer_map':
                    ast = new CreateIntMap();
                    break;
            }
            ast.setElementType(getFieldText(block.fields.ELEMENT_TYPE));
            return ast;
        },

        struct_list_get_value_at_index(block) {
            if (!(blockIntputs(block) && blockIntputs(block).LIST)) {
                this._stack.markError(block, '必须提供列表');
            }
            if (!(blockIntputs(block) && blockIntputs(block).INDEX)) {
                this._stack.markError(block, '必须提供索引');
            }
            let list = BlocktoExpr(this._stack, block, blockIntputs(block).LIST);
            let index = BlocktoExpr(this._stack, block, blockIntputs(block).INDEX);
            let ast = new ValueAt(list, index);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_list_set_value_at_index(block) {
            if (!(blockIntputs(block) && blockIntputs(block).LIST)) {
                this._stack.markError(block, '必须提供列表');
            }
            if (!(blockIntputs(block) && blockIntputs(block).INDEX)) {
                this._stack.markError(block, '必须提供索引');
            }
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供值');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            let idx = BlocktoExpr(this._stack, block, blockIntputs(block).INDEX);
            let list = BlocktoExpr(this._stack, block, blockIntputs(block).LIST);
            let ast = new SVAT(list, idx, value);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_list_insert_value_at_index(block) {
            if (!(blockIntputs(block) && blockIntputs(block).LIST)) {
                this._stack.markError(block, '必须提供列表');
            }
            if (!(blockIntputs(block) && blockIntputs(block).INDEX)) {
                this._stack.markError(block, '必须提供索引');
            }
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供值');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            let idx = BlocktoExpr(this._stack, block, blockIntputs(block).INDEX);
            let list = BlocktoExpr(this._stack, block, blockIntputs(block).LIST);
            let ast = new IVAT(list, idx, value);
            ast.setBlockId(block.id);
            return ast;
        },
        struct_list_delete_value_at_index(block) {
            if (!(blockIntputs(block) && blockIntputs(block).LIST)) {
                this._stack.markError(block, '必须提供列表');
            }
            if (!(blockIntputs(block) && blockIntputs(block).INDEX)) {
                this._stack.markError(block, '必须提供索引');
            }
            let idx = BlocktoExpr(this._stack, block, blockIntputs(block).INDEX);
            let list = BlocktoExpr(this._stack, block, blockIntputs(block).LIST);
            let ast = new RVAT(list, idx);
            ast.setBlockId(block.id);
            return ast;
        },
        /**
         * openblock变量必须初始化，此命令不再有意义
         */
        logic_var_assigned(block) {
            if (!(blockIntputs(block) && blockIntputs(block).VALUE)) {
                this._stack.markError(block, '必须提供变量');
            }
            let value = BlocktoExpr(this._stack, block, blockIntputs(block).VALUE);
            let ast = new VarAssigned();
            ast.setValue(value);
            ast.setBlockId(block.id);
            return ast;
        },
        text_log(block) {
            if (!(blockIntputs(block) && blockIntputs(block).MSG)) {
                this._stack.markError(block, '必须指定消息');
            }
            let methodName = 'SYS_LOG';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let msg = BlocktoExpr(this._stack, block, blockIntputs(block).MSG, "必须提供值");
            let level = parseInt(getFieldText(block.fields.LEVEL));
            let a_level = new IntegerConstExpr();
            a_level.number = level;
            let ast = new VoidNativeCall();
            ast.setFunc(func);
            ast.setArg('msg', msg);
            ast.setArg('level', a_level);
            ast.setBlockId(block.id);
            return ast;
        },
        set_fsm_priority(block) {
            if (!(blockIntputs(block) && blockIntputs(block).priority)) {
                this._stack.markError(block, '必须指定优先级');
            }
            let methodName = 'set_fsm_priority';
            let func = OpenBlock.Env.findBuildInFunction(methodName);

            let priority = BlocktoExpr(this._stack, block, blockIntputs(block).priority, "必须指定优先级");
            let ast = new VoidNativeCall();
            ast.setFunc(func);
            ast.setArg('priority', priority);
            ast.setBlockId(block.id);
            return ast;
        },
        get_fsm_priority(block) {
            let methodName = 'get_fsm_priority';
            let func = OpenBlock.Env.findBuildInFunction(methodName);
            let ast = new ValueNativeCall();
            ast.setFunc(func);
            ast.setBlockId(block.id);
            return ast;
        },
    };
});